/**
 * 暴露给外部的方法
 * 
 * getLinkInfo：根据路由规则生成link元素列表 
 * nameToPathConfig：根据name获取配置对象
 * pathToConfig: 根据path获取配置对象
 * getRoutes: 获取某一层的Route列表
 * configsToRoutes: 将配置数组转换为 route 数组
 * 获取一级路由中有子路的数组列表 
 */
import { perfectConfig, oneConfigs } from './init'
import { NavLink, Route } from 'react-router-dom'
import { fileTree, Asidelinks } from '.'
import { configUniq, getFileConfigs } from './utils'


/**
 * 根据路由规则生成link元素列表
 * @param {Array} rules 路由规则数组
 * @param {String} baseUrl 基础路径
 * @param {Array} _open 层级数组 记录了层级信息
 * @param {boolean} isOne 是否第一层
 */
export function getLinkInfo(rules, baseUrl = "", _open = [], isOne) {
    if (!Array.isArray(rules)) {
        throw new Error(`rules is not Array`)
    }
    return rules.map(obj => {
        let { path, name, componentsFileName, children, noAside, meta } = perfectConfig(obj);
        path = baseUrl + path
        const open = [..._open, name]
        path = path.replace(/\/\//g, '/')
        let child = []

        // 只处理一级目录 
        if (isOne) {
            const { configs } = getFileConfigs(fileTree, componentsFileName)
            children = configUniq([...children, ...configs])
        }

        if (children.length) {
            child = getLinkInfo(children, path, open)
        }
        return { path, open, child, noAside, link: <NavLink to={path}>{meta.title}</NavLink>, config: obj }
    })
}



/**
 * 根据name获取配置对象
 * @param {string} name 
 * @param {object} links 
 * @returns 返回配置对象
 */
export function nameToPathConfig(name, links = Asidelinks) {
    function _help(name, arr) {
        for (let i = 0; i < arr.length; i++) {
            const obj = arr[i];
            if (obj.config.name === name) {
                return obj
            } else if (obj.child && obj.child.length) {
                const res = _help(name, obj.child)
                if (res) return res
            }
        }
    }
    const obj = _help(name, links)
    return obj
}


/**
 * 根据path获取配置对象
 * @param {string} path 
 * @returns 返回配置对象
 */
export function pathToConfig(path, links = Asidelinks) {
    function _help(path, arr) {
        for (let i = 0; i < arr.length; i++) {
            const obj = arr[i];
            if (obj.path === path) {
                return obj
            } else if (obj.child && obj.child.length) {
                const res = _help(path, obj.child)
                if (res) return res
            }
        }
    }
    const obj = _help(path, links)
    return obj
}


/**
 * 获取某一层的Route列表
 * @param {string} name 
 * @returns 
 */
export function getRoutes(name = 'admin') {
    let child = []
    if (name === 'admin') {
        child = Asidelinks
    } else {
        const obj = nameToPathConfig(name) || {}
        if (!obj) throw new Error(`adminRules 中没有 name：【${name}】对应的规则 `)
        child = obj.child
    }
    return configsToRoutes(child)
}


/**
 * 将配置数组转换为 route 数组
 * @param {array} arr 配置数组
 */
export function configsToRoutes(arr) {
    return arr.map(({ path, config: { component, exact = true, name }, child }, i) => {
        if (!component && child.length) {
            return getRoutes(name)
        }
        return <Route key={i} exact={exact} path={path} component={component} />
    })
}


/**
 * 获取一级路由中有子路的数组列表 
 * 获取展开映射
 * @returns 
 */
export function getOpenOneList() {
    function _getlist(list = oneConfigs) {
        const arr = list.filter(t => {
            if (t.children) {
                const childArr = t.children.filter(c => !c.noAside)
                return childArr && childArr.length
            }
            return false
        }).map(t => {
            const childArr = t.children.filter(c => !c.noAside)
            const child = _getlist(childArr) || []
            const result = [t.name, ...child]
            return result
        })

        return arr
    }
    function treeMap(tree, base = [], obj = {}) {
        tree.forEach(t => {
            const [name, ...childs] = t
            obj[name] = [...base, name]
            treeMap(childs, obj[name], obj)
        });
        return obj
    }
    const tree = _getlist()
    return { scope: tree.flat(), map: treeMap(tree) }
}

